/**
 * Software License, Version 1.0 Copyright 2003 The Trustees of Indiana
 * University. All rights reserved. Redistribution and use in source and binary
 * forms, with or without modification, are permitted provided that the
 * following conditions are met: 1) All redistributions of source code must
 * retain the above copyright notice, the list of authors in the original source
 * code, this list of conditions and the disclaimer listed in this license; 2)
 * All redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the disclaimer listed in this license in the
 * documentation and/or other materials provided with the distribution; 3) Any
 * documentation included with all redistributions must include the following
 * acknowledgement: "This product includes software developed by the Community
 * Grids Lab. For further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/." Alternatively, this acknowledgement may
 * appear in the software itself, and wherever such third-party acknowledgments
 * normally appear. 4) The name Indiana University or Community Grids Lab or
 * NaradaBrokering, shall not be used to endorse or promote products derived
 * from this software without prior written permission from Indiana University.
 * For written permission, please contact the Advanced Research and Technology
 * Institute ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202. 5)
 * Products derived from this software may not be called NaradaBrokering, nor
 * may Indiana University or Community Grids Lab or NaradaBrokering appear in
 * their name, without prior written permission of ARTI. Indiana University
 * provides no reassurances that the source code provided does not infringe the
 * patent or any other intellectual property rights of any other entity. Indiana
 * University disclaims any liability to any recipient for claims brought by any
 * other entity based on infringement of intellectual property rights or
 * otherwise. LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH
 * NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY
 * GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 * INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 * INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 * "VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 * LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 * ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 * GENERATED USING SOFTWARE.
 */
package cgl.narada.samples.secureAV;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.Random;
import java.util.TimeZone;

import cgl.narada.discovery.topics.Entity;
import cgl.narada.discovery.topics.TopicDiscoveryClient;
import cgl.narada.discovery.topics.Topics;
import cgl.narada.discovery.topics.messages.SignedTopicAdvertisement;
import cgl.narada.event.TemplateProfileAndSynopsisTypes;
import cgl.narada.service.security.kmc.KMCClient;
import cgl.narada.service.security.kmc.SignedSecurityToken;
import cgl.narada.service.security.kmc.TopicRights;
import cgl.narada.service.security.kmc.messages.SecureTopicKeyResponse;
import cgl.narada.service.security.securityprovider.CertificateManager;
import cgl.narada.service.security.securityprovider.CertificateUtil;
import cgl.narada.util.SystemInit;
import cgl.narada.util.SystemNotInitializedException;

// HG: Added security stuff to original code by Hasan bulut

public class SecureTopicsKeyGenerator {

	public String host = "localhost", port = "25000", protocol = "niotcp";

	String serviceConfigPath;

	public SecureTopicsKeyGenerator(String data, String control, String a,
			String h, String p, String pr) {
		topicNameData = data;
		topicNameControl = control;
		alias = a;

		String keystore = null;
		try {
			keystore = SystemInit.getInitData(SystemInit.SYS_KEYSTORE);
			serviceConfigPath = SystemInit
					.getInitData(SystemInit.SYS_SERVICE_CONFIG_PATH);
		}
		catch (SystemNotInitializedException e) {
			e.printStackTrace();
		}

		initKeyStore(keystore);

		if (h != null) host = h;
		if (p != null) port = p;
		if (pr != null) protocol = pr;
	}

	public String topicUUIDData, topicUUIDControl;
	public String topicNameData, topicNameControl;
	public SecureTopicKeyResponse stkData, stkControl;
	public PublicKey rootCA;
	public Certificate c_cert;
	public PrivateKey c_priv;

	private String alias;

	private void initKeyStore(String keystore) {
		CertificateManager certMan = new CertificateManager();
		certMan.init(keystore, null);

		rootCA = CertificateUtil.getPublicKey(certMan, certMan.ROOT_CA_ALIAS);

		c_cert = CertificateUtil.getCertificate(certMan, alias);
		c_priv = CertificateUtil.getPrivateKey(certMan, alias);
	}

	public void genTopicsAndKeys() {
		KMCClient client2 = new KMCClient(c_cert, c_priv, rootCA, "/kmc/"
				+ alias, serviceConfigPath, host, port, protocol);

		// === FOR DATA ===

		// First discover the topic...
		SignedTopicAdvertisement[] stasD = discoverTopics(c_cert, c_priv,
				topicNameData, Topics.MATCHING_STRING, 1);

		TopicRights reqRightsD = new TopicRights(TopicRights.SUBSCRIBE_RIGHT);

		// Now try to get the security token...
		stkData = client2.requestTopicKey(stasD[0].getTopicAd()
				.getTopicSynopsis(), c_cert, reqRightsD, 5000);

		if (stkData == null)
			System.out.println("Request Denied / Timeout occurred !");
		else {
			System.out.println("Sec Token:"
					+ stkData.getSignedSecurityToken().getSecurityToken()
							.getValidity().toString());

			topicUUIDData = stasD[0].getTopicAd().getTopicSynopsis();

		}

		// === -x- ===

		// === FOR CONTROL ===

		// First discover the topic...
		SignedTopicAdvertisement[] stasC = discoverTopics(c_cert, c_priv,
				topicNameControl, Topics.MATCHING_STRING, 1);

		TopicRights reqRightsC = new TopicRights(TopicRights.SUBSCRIBE_RIGHT
				+ TopicRights.PUBLISH_RIGHT);

		// Now try to get the security token...
		stkControl = client2.requestTopicKey(stasC[0].getTopicAd()
				.getTopicSynopsis(), c_cert, reqRightsC, 5000);

		if (stkControl == null)
			System.out.println("Request Denied / Timeout occurred !");
		else {
			System.out.println("Sec Token:"
					+ stkControl.getSignedSecurityToken().getSecurityToken()
							.getValidity().toString());

			topicUUIDControl = stasC[0].getTopicAd().getTopicSynopsis();

		}

		// === -x- ===

		client2.close();
	}

	public SignedTopicAdvertisement[] discoverTopics(Certificate cert,
			PrivateKey priv, String synopsis, int matchType, int maxTopics) {

		TopicDiscoveryClient disco = new TopicDiscoveryClient(15000,
				serviceConfigPath, cert, priv, host, port, protocol);

		SignedTopicAdvertisement[] stas = disco.discover(matchType, synopsis,
				null, maxTopics);

		disco.close();

		return stas;
	}

	Entity e;
	KMCClient client;

	public void generateTopics(String algo, int keylen, int timeoutMins1,
			int timeoutMins2) {

		Calendar until1 = Calendar.getInstance(TimeZone.getTimeZone("GMT-5"));
		until1.add(Calendar.MINUTE, timeoutMins1);

		Calendar until2 = Calendar.getInstance(TimeZone.getTimeZone("GMT-5"));
		until2.add(Calendar.MINUTE, timeoutMins2);

		e = new Entity((new Random()).nextInt(), serviceConfigPath, alias,
				c_cert, c_priv, rootCA, host, port, protocol);

		if (e.sendTDNDiscoveryRequest(10000)) {
			System.out.println("Found TDN ! Proceeding to create TOPIC !!");
		}
		else {
			System.out
					.println("NO TDN found within specified timeout period !!");
		}

		client = new KMCClient(c_cert, c_priv, rootCA, "/kmc/" + alias,
				serviceConfigPath, host, port, protocol);

		stkData = createTopicAndSecurityToken(until1, until1, until2,
				topicNameData, algo, keylen, true);
		stkControl = createTopicAndSecurityToken(until1, until1, until2,
				topicNameControl, algo, keylen, false);

		e.close();
		client.close();
	}

	private SecureTopicKeyResponse createTopicAndSecurityToken(Calendar until,
			Calendar until1, Calendar until2, String topicName, String algo,
			int keylen, boolean dataTopic) {

		if (e == null) {
			System.out.println("ERRRORRRR !!!!");
			return null;
		}

		System.out.println("**** CREATING TOPIC: " + topicName);
		createTopic(e, topicName, TemplateProfileAndSynopsisTypes.STRING, until);

		// Get Signed Topic Ad
		SignedTopicAdvertisement sta = e.getSignedTopicAdvertisement(topicName);

		if (dataTopic) {
			topicUUIDData = sta.getTopicAd().getTopicSynopsis();
		}
		else
			topicUUIDControl = sta.getTopicAd().getTopicSynopsis();

		// Set the access control lists
		Hashtable pubs = new Hashtable();
		pubs.put(((X509Certificate) c_cert).getSubjectDN().getName(), until);
		if (topicName.startsWith("Media/Control")) {
			pubs.put("CN=client2, OU=CGL, O=IU, L=Bloomington, C=US", until1);
			pubs.put("CN=client3, OU=DistLab, O=NYC, L=NewYork, C=US", until2);
		}

		Hashtable subs = new Hashtable();
		subs.put(((X509Certificate) c_cert).getSubjectDN().getName(), until);
		subs.put("CN=client2, OU=CGL, O=IU, L=Bloomington, C=US", until1);
		subs.put("CN=client3, OU=DistLab, O=NYC, L=NewYork, C=US", until2);

		// Ok, now register the topic and get a security token
		SecureTopicKeyResponse resp = client.registerTopic(pubs, subs, sta,
				c_cert, until, algo, keylen, 5000);

		// Check the response
		SignedSecurityToken tok = resp.getSignedSecurityToken();
		System.out.println("VERIFICATION: " + tok.verify());
		System.out.println("Publish: "
				+ tok.getSecurityToken().getRights().hasPublishRight());
		System.out.println("Subscribe: "
				+ tok.getSecurityToken().getRights().hasSubscribeRight());

		return resp;
	}

	public boolean createTopic(Entity e, String topicName, int topicType,
			Calendar until) {

		if (!e.createTopic("SELF", until, "Test Topic", topicType, topicName,
				null, 5000)) {
			System.err.println("Could not create topic ! Aborting...");
			return false;
		}

		System.out.println("TOPIC Created: UUID -> "
				+ e.getTopicUUID(topicName));
		return true;

	}
}